---
title: Subscriptions
description: Get real-time updates from your GraphQL server
---

{/* @import {MDXProvidedComponents} from '../../shared/MdxProvidedComponents.js' */}

In addition to [queries](./queries/) and [mutations](./mutations/), GraphQL supports a third operation type: **subscriptions**.

Like queries, subscriptions enable you to fetch data. _Unlike_ queries, subscriptions are long-lasting operations that can change their result over time. They can maintain an active connection to your GraphQL server (most commonly via WebSocket), enabling the server to push updates to the subscription's result.

Subscriptions are useful for notifying your client in real time about changes to back-end data, such as the creation of a new object or updates to an important field.

## When to use subscriptions

In the majority of cases, your client should _not_ use subscriptions to stay up to date with your backend. Instead, you should [poll intermittently](./queries/#polling) with queries, or [re-execute queries on demand](./queries/#refetching) when a user performs a relevant action (such as clicking a button).

You _should_ use subscriptions for the following:

- **Small, incremental changes to large objects**. Repeatedly polling for a large object is expensive, especially when most of the object's fields rarely change. Instead, you can fetch the object's initial state with a query, and your server can proactively push updates to individual fields as they occur.

- **Low-latency, real-time updates**. For example, a chat application's client wants to receive new messages as soon as they're available.

<Note>

Subscriptions cannot be used to listen to local client events, like subscribing to changes in the cache. Subscriptions are intended to be used to subscribe to external data changes, and have those received changes be stored in the cache. You can then leverage Apollo Client's observability model to watch for changes in the cache, using [`client.watchQuery`](../api/core/ApolloClient#ApolloClient.watchQuery), [`useQuery`](../api/react/hooks#usequery), or [`useFragment`](../api/react/useFragment).

</Note>

## Supported subscription protocols

The GraphQL spec does not define a specific protocol for sending subscription requests. Apollo Client supports the following protocols for subscriptions:

- [**WebSocket**](#websocket-subprotocols), using one of the following subprotocols:
  - [`graphql-ws`](https://github.com/enisdenjo/graphql-ws)
  - [`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws) (⚠️ unmaintained)
- [**HTTP**](#http), using chunked multipart responses

> **You must use the same protocol as the GraphQL endpoint you're communicating with.**

### WebSocket subprotocols

The first popular JavaScript library to implement subscriptions over WebSocket is called `subscriptions-transport-ws`. **This library is no longer actively maintained.** Its successor is a library called `graphql-ws`. These two libraries _do not use the same WebSocket subprotocol_, so you need to use the same subprotocol that your GraphQL endpoint uses.

The [WebSocket setup](#websocket-setup) section below uses `graphql-ws`. If your endpoint uses `subscriptions-transport-ws`, see [this section](#the-older-subscriptions-transport-ws-library) for differences in configuration.

> **Note**: Confusingly, the `subscriptions-transport-ws` library calls its _WebSocket subprotocol_ `graphql-ws`, and the `graphql-ws` _library_ calls its subprotocol `graphql-transport-ws`! In this article, we refer to the two _libraries_ (`subscriptions-transport-ws` and `graphql-ws`), _not_ the two subprotocols.

### HTTP

Apollo Client provides out-of-the-box support for [multipart subscriptions over HTTP](https://github.com/graphql/graphql-over-http/blob/main/rfcs/IncrementalDelivery.md) when using [`HttpLink`](../api/link/apollo-link-http) as your [terminating link](../api/link/introduction#the-terminating-link). No additional configuration is required! Apollo Client automatically sends the required headers with the request if the terminating `HttpLink` is passed a subscription operation.

#### Usage with Relay

To consume a multipart subscription over HTTP in an app using Relay, Apollo Client provides network layer adapters that handle the parsing of the multipart response format.

##### Relay

<MultiCodeBlock>

```ts
import { createFetchMultipartSubscription } from "@apollo/client/utilities/subscriptions/relay";
import { Environment, Network, RecordSource, Store } from "relay-runtime";

const fetchMultipartSubs = createFetchMultipartSubscription(
  "https://api.example.com"
);

const network = Network.create(fetchQuery, fetchMultipartSubs);

export const RelayEnvironment = new Environment({
  network,
  store: new Store(new RecordSource()),
});
```

</MultiCodeBlock>

## Defining a subscription

In your application's client, you provide a GraphQL document with a `subscription` operation type:

<MultiCodeBlock>

```ts
const COMMENTS_SUBSCRIPTION: TypedDocumentNode<
  OnCommentAddedSubscription,
  OnCommentAddedSubscriptionVariables
> = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;
```

```js
const COMMENTS_SUBSCRIPTION = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;
```

</MultiCodeBlock>

When Apollo Client executes the `OnCommentAdded` subscription, it establishes a connection to your GraphQL server and listens for response data. Unlike a query, there is no expectation that the server will immediately process and return a response. Instead, your server only pushes data to your client when a particular event occurs on your backend.

When your GraphQL server pushes data to the client, that object conforms to the [GraphQL response format](https://spec.graphql.org/October2021/#sec-Response-Format), just like it does for a query:

```json
{
  "data": {
    "commentAdded": {
      "id": "123",
      "content": "What a thoughtful and well written post!"
    }
  }
}
```

## WebSocket setup

### 1. Install required libraries

[Apollo Link](../api/link/introduction/) is a library that helps you customize Apollo Client's network communication. You can use it to define a **link chain** that modifies your operations and routes them to the appropriate destination.

To execute subscriptions over WebSocket, you can add a `GraphQLWsLink` to your link chain. This link requires the `graphql-ws` library. Install it like so:

```bash
npm install graphql-ws
```

### 2. Initialize a `GraphQLWsLink`

Import and initialize a `GraphQLWsLink` object in the same project file where you initialize `ApolloClient`:

<MultiCodeBlock>

```ts title="index.ts"
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const wsLink = new GraphQLWsLink(
  createClient({
    url: "ws://localhost:4000/subscriptions",
  })
);
```

</MultiCodeBlock>

Replace the value of the `url` option with your GraphQL server's subscription-specific WebSocket endpoint. If you're using Apollo Server, see [Setting a subscription endpoint](/apollo-server/data/subscriptions/#enabling-subscriptions).

### 3. Split communication by operation (recommended)

Although Apollo Client can use your `GraphQLWsLink` to execute all operation types, in most cases it should continue using HTTP for queries and mutations. This is because queries and mutations don't require a stateful or long-lasting connection, making HTTP more efficient and scalable if a WebSocket connection isn't already present.

To support this, the `@apollo/client` library provides a `split` function that lets you use one of two different `Link`s, according to the result of a boolean check.

The following example expands on the previous one by initializing both a `GraphQLWsLink` _and_ an `HttpLink`. It then uses the `split` function to combine those two `Link`s into a _single_ `Link` that uses one or the other according to the type of operation being executed.

<MultiCodeBlock>

```ts title="index.ts"
import { OperationTypeNode } from "graphql";
import { ApolloLink, HttpLink } from "@apollo/client";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const httpLink = new HttpLink({
  uri: "http://localhost:4000/graphql",
});

const wsLink = new GraphQLWsLink(
  createClient({
    url: "ws://localhost:4000/subscriptions",
  })
);

// The split function takes three parameters:
//
// * A function that's called for each operation to execute
// * The Link to use for an operation if the function returns a "truthy" value
// * The Link to use for an operation if the function returns a "falsy" value
const splitLink = ApolloLink.split(
  ({ operationType }) => {
    return operationType === OperationTypeNode.SUBSCRIPTION;
  },
  wsLink,
  httpLink
);
```

</MultiCodeBlock>

Using this logic, queries and mutations will use HTTP as normal, and subscriptions will use WebSocket.

### 4. Provide the link chain to Apollo Client

After you define your link chain, you provide it to Apollo Client via the `link` constructor option:

<MultiCodeBlock>

```ts {6} title="index.ts"
import { ApolloClient, InMemoryCache } from "@apollo/client";

// ...code from the above example goes here...

const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});
```

```js {6} title="index.js"
import { ApolloClient, InMemoryCache } from "@apollo/client";

// ...code from the above example goes here...

const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});
```

</MultiCodeBlock>

### 5. Authenticate over WebSocket (optional)

It is often necessary to authenticate a client before allowing it to receive subscription results. To do this, you can provide a `connectionParams` option to the `GraphQLWsLink` constructor, like so:

<MultiCodeBlock>

```ts {6-8}
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const wsLink = new GraphQLWsLink(
  createClient({
    url: "ws://localhost:4000/subscriptions",
    connectionParams: {
      authToken: user.authToken,
    },
  })
);
```

```js {6-8}
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const wsLink = new GraphQLWsLink(
  createClient({
    url: "ws://localhost:4000/subscriptions",
    connectionParams: {
      authToken: user.authToken,
    },
  })
);
```

</MultiCodeBlock>

Your `GraphQLWsLink` passes the `connectionParams` object to your server whenever it connects. Your server receives the `connectionParams` object and can use it to perform authentication, along with any other connection-related tasks.

## Subscriptions via multipart HTTP

No additional libraries or configuration are required. Apollo Client adds the required headers to your request when the default terminating `HTTPLink` receives a subscription operation at the `uri` specified when initializing the link or Apollo Client instance.

<Note>

In order to use subscriptions over multipart HTTP in a React Native application, additional configuration is required. See the [React Native docs](../integrations/react-native#consuming-multipart-http-via-text-streaming) for more information.

</Note>

## Executing a subscription

You use the [`useSubscription`](../api/react/useSubscription) hook to execute a subscription. Like [`useQuery`](./queries/#executing-a-query), `useSubscription` returns an object from Apollo Client that contains `loading`, `error`, and `data` properties you can use to render your UI.

The following example component uses the subscription we defined earlier to render the most recent comment that's been added to a specified blog post. Whenever the GraphQL server pushes a new comment to the client, the component re-renders with the new comment.

<MultiCodeBlock>

```tsx
const COMMENTS_SUBSCRIPTION: TypedDocumentNode<
  OnCommentAddedSubscription,
  OnCommentAddedSubscriptionVariables
> = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;

function LatestComment({ postID }: LatestCommentProps) {
  const { data, loading } = useSubscription(COMMENTS_SUBSCRIPTION, {
    variables: { postID },
  });

  return <h4>New comment: {!loading && data.commentAdded.content}</h4>;
}
```

```jsx
const COMMENTS_SUBSCRIPTION = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;

function LatestComment({ postID }) {
  const { data, loading } = useSubscription(COMMENTS_SUBSCRIPTION, {
    variables: { postID },
  });

  return <h4>New comment: {!loading && data.commentAdded.content}</h4>;
}
```

</MultiCodeBlock>

## Subscribing to updates for a query

Whenever a query returns a result in Apollo Client, that result includes a `subscribeToMore` function. You can use this function to execute a followup subscription that pushes updates to the query's original result.

<Note>

The `subscribeToMore` function is similar in structure to the [`fetchMore`](../caching/advanced-topics/#incremental-loading-fetchmore) function that's commonly used for handling pagination. The primary difference is that `fetchMore` executes a followup _query_, whereas `subscribeToMore` executes a subscription.

</Note>

As an example, let's start with a standard query that fetches all of the existing comments for a given blog post:

<MultiCodeBlock>

```tsx
const COMMENTS_QUERY: TypedDocumentNode<
  CommentsForPostQuery,
  CommentsForPostQueryVariables
> = gql`
  query CommentsForPost($postID: ID!) {
    post(postID: $postID) {
      comments {
        id
        content
      }
    }
  }
`;

function CommentsPageWithData({ params }: CommentsPageWithDataProps) {
  const result = useQuery(COMMENTS_QUERY, {
    variables: { postID: params.postID },
  });

  return <CommentsPage {...result} />;
}
```

```jsx
const COMMENTS_QUERY = gql`
  query CommentsForPost($postID: ID!) {
    post(postID: $postID) {
      comments {
        id
        content
      }
    }
  }
`;

function CommentsPageWithData({ params }) {
  const result = useQuery(COMMENTS_QUERY, {
    variables: { postID: params.postID },
  });

  return <CommentsPage {...result} />;
}
```

</MultiCodeBlock>

Let's say we want our GraphQL server to push an update to our client as soon as a _new_ comment is added to the post. First we need to define the subscription that Apollo Client will execute when the `COMMENTS_QUERY` returns:

<MultiCodeBlock>

```tsx
const COMMENTS_SUBSCRIPTION: TypedDocumentNode<
  OnCommentAddedSubscription,
  OnCommentAddedSubscriptionVariables
> = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;
```

```jsx
const COMMENTS_SUBSCRIPTION = gql`
  subscription OnCommentAdded($postID: ID!) {
    commentAdded(postID: $postID) {
      id
      content
    }
  }
`;
```

</MultiCodeBlock>

Next, we modify our `CommentsPageWithData` component to call `subscribeToMore` after the comments query loads.

<MultiCodeBlock>

```tsx {10-23}
function CommentsPageWithData({ params }: CommentsPageWithDataProps) {
  const { subscribeToMore, ...result } = useQuery(COMMENTS_QUERY, {
    variables: { postID: params.postID },
  });

  useEffect(() => {
    // This assumes you want to wait to start the subscription
    // after the query has loaded.
    if (result.data) {
      const unsubscribe = subscribeToMore({
        document: COMMENTS_SUBSCRIPTION,
        variables: { postID: params.postID },
        updateQuery: (prev, { subscriptionData }) => {
          if (!subscriptionData.data) return prev;
          const newFeedItem = subscriptionData.data.commentAdded;

          return Object.assign({}, prev, {
            post: {
              comments: [newFeedItem, ...prev.post.comments],
            },
          });
        },
      });

      return () => {
        unsubscribe();
      };
    }
  }, [result.data, params.postID, subscribeToMore]);

  return <CommentsPage {...result} />;
}
```

```jsx {10-25}
function CommentsPageWithData({ params }) {
  const { subscribeToMore, ...result } = useQuery(COMMENTS_QUERY, {
    variables: { postID: params.postID },
  });

  useEffect(() => {
    if (result.data) {
      const unsubscribe = subscribeToMore({
        document: COMMENTS_SUBSCRIPTION,
        variables: { postID: params.postID },
        updateQuery: (prev, { subscriptionData }) => {
          if (!subscriptionData.data) return prev;
          const newFeedItem = subscriptionData.data.commentAdded;

          return Object.assign({}, prev, {
            post: {
              comments: [newFeedItem, ...prev.post.comments],
            },
          });
        },
      });

      return () => {
        unsubscribe();
      };
    }
  }, [result.data, params.postID]);

  return <CommentsPage {...result} />;
}
```

</MultiCodeBlock>

In the example above, we pass three options to `subscribeToMore`:

- `document` indicates the subscription to execute.
- `variables` indicates the variables to include when executing the subscription.
- `updateQuery` is a function that tells Apollo Client how to combine the query's currently cached result (`prev`) with the `subscriptionData` that's pushed by our GraphQL server. The return value of this function **completely replaces** the current cached result for the query.

## `useSubscription` API reference

### Options

The `useSubscription` Hook accepts the following options:

<PropertySignatureTable
  canonicalReference="@apollo/client/react!useSubscription.DocumentationTypes.useSubscription.Options:interface"
  idPrefix="subscriptionhookoptions-interface"
/>

### Result

After being called, the `useSubscription` Hook returns a result object with the following properties:

<PropertySignatureTable
  canonicalReference="@apollo/client/react!useSubscription.Result:interface"
  idPrefix="subscriptionresult-interface"
/>

## The older `subscriptions-transport-ws` library

If your server uses `subscriptions-transport-ws` instead of the newer `graphql-ws` library, you need to make a few changes to how you set up your link:

1. Instead of `npm install graphql-ws`:

   ```bash
   npm install subscriptions-transport-ws
   ```

2. Instead of `import { createClient } from 'graphql-ws'`:

   ```js
   import { SubscriptionClient } from "subscriptions-transport-ws";
   ```

3. Instead of `import { GraphQLWsLink } from '@apollo/client/link/subscriptions'`:

   ```js
   import { WebSocketLink } from "@apollo/client/link/ws";
   ```

4. The options you pass to `new SubscriptionClient` differ slightly from those passed to `createClient`:

   - The first argument passed to the `SubscriptionClient` constructor is the URL for your subscription server.
   - The `connectionParams` option is nested under an options object called `options` instead of being at the top level. (You can also pass the `new SubscriptionClient` constructor arguments directly to `new WebSocketLink`.)
   - See [the `subscriptions-transport-ws` README](https://www.npmjs.com/package/subscriptions-transport-ws) for complete `SubscriptionClient` API docs.

After you create your `wsLink`, everything else in this article still applies: `useSubscription`, `subscribeToMore`, and split links work exactly the same way for both implementations.

The following is an example of a typical `WebSocketLink` initialization:

<MultiCodeBlock>

```ts
import { WebSocketLink } from "@apollo/client/link/ws";
import { SubscriptionClient } from "subscriptions-transport-ws";

const wsLink = new WebSocketLink(
  new SubscriptionClient("ws://localhost:4000/subscriptions", {
    connectionParams: {
      authToken: user.authToken,
    },
  })
);
```

</MultiCodeBlock>

More details on `WebSocketLink`'s API can be found in [its API docs](../api/link/apollo-link-ws).
